package edu.siu.math.egut.util;


import java.io.Serializable;
import java.util.Arrays;
import java.util.Map;
import java.util.WeakHashMap;



/**
 * The Class Sunipotent:  short for "Simple Unipotent";
 * logical part of a "unipotent." Let $G$ be a split connected reductive
 * algebraic group over a field F, equipped with a choice of maximal torus (used
 * to define roots) and a choice of Borel (used to define a base of simple
 * roots). To each root a there is associated a one-dimensional unipotent
 * subgroup U_a, isomorphic to the additive group-scheme. The class Sunipotent
 * models elements of these subgroups. Specifically, we take G to be equipped,
 * in addition, with a Chevalley-Steinberg system of epinglage, i.e., a family
 * of specific isomorphisms x_a between the subgroups U_a and the additive
 * group-scheme, subject to certain compatibility conditions. Then an element of
 * U_a(A) (for A an F-algebra) is of the form x_a(r), with r in A. To model this
 * and facilitate symbolic manipulation, a Sunipotent has two attributes: a
 * root, and an "argument" which is simply a polynomial.
 * 
 * @author Joe Pleso
 */
 final class SimpleUnipotentElement implements Serializable {
   

    /**
     * 
     */
    private static final long serialVersionUID = 220L;



    private final int[] a;

   
    
    private LaurentPolynomial p;

    private static final Map<SimpleUnipotentElement, Object> sunipotents = 
	new WeakHashMap<SimpleUnipotentElement, Object>();
    /**
     * Instantiates a new sunipotent.
     * 
     * @param i                the root from the rootsystem
     * @param poly                     the polynomial
     * 
     * @return the specified sunipotent
     */
    public static SimpleUnipotentElement create(
	    int[] i, LaurentPolynomial poly) {
	for (SimpleUnipotentElement s : sunipotents.keySet())
	    if (Arrays.equals(s.a, i) && s.p == poly)
		return s;
	return new SimpleUnipotentElement(i, poly);
    }



    /**
     * Instantiates a new sunipotent.
     * 
     * @param i                root from a root system
     * @param poly                the polynomial
     */
    private SimpleUnipotentElement(int[] i, 
	    LaurentPolynomial poly
	   ) {
	a = i;
	p = poly;


    }
    /**
     * Tests if two sunipotents are equal.
     * 
     * @param s the other sunipotent to test
     * @return true if the sunipotents are equal
     */
    public boolean equals(SimpleUnipotentElement s){

	return (s.getPolynomial().equals(getPolynomial()))
	&&Arrays.equals(s.getRoot(), getRoot());
    }
    /**
     * Gets the polynomial.
     * 
     * @return the polynomial
     */
    public LaurentPolynomial getPolynomial() {
	return p;
    }

    

    /**
     * Gets the root.
     * 
     * @return the root
     */
    public int[] getRoot() {
	int[] root = new int[a.length];
	for (int i = 0; i < a.length; i++)
	    root[i] = a[i];
	return root;
    }

    public String toString() {
	return toShortString();
    }
    private  String toShortString(){

	StringBuffer sb = new StringBuffer();
	int[] a = getRoot();
	int sign = 1;
	if( ExceptionalGroup.isNegative(a) ){
	    sb.append("-");
	    sign = -1;
	}
	for( int i = 0 ; i < a.length; i++)
	{
	    sb.append(a[i]*sign);
	}
	sb.append("("+getPolynomial()+")");

	return sb.toString();
    }
    




    /**
     * Replaces the polynomial.
     * 
     * @param x variable to substitute for
     * @param f the substitution
     * @return the element of the group
     *
     */
    public SimpleUnipotentElement replace(String x,
	    LaurentPolynomial f) {
	return create (a,p.replace( x, f));
    }



    public String toTex() {
	StringBuffer sb = new StringBuffer();
	int[] a = getRoot();
	LaurentPolynomial root = LaurentPolynomial.rootToPolynomial(a);
	
	
	sb.append("\\chi_{" 
		+ root.toString()
		+ "}("+getPolynomial()+")");

	return sb.toString();
    }


}
